/**
* \file DGVSurfacePlotVTK.cpp
*
* \brief This file defines a class for display Surface Plots using VTK.
* \author Shekhar S. Chandra, 2008
*
* This file is part of DGV Library.
*
* DGV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DGV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DGV.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "DGVSurfacePlotVTK.h"

#include "vtkMergeFilter.h"
#include "vtkImageThreshold.h"
#include "vtkProperty2D.h"
#include "vtkTextProperty.h"
#include "vtkXMLImageDataWriter.h"

DGVSurfacePlotVTK::DGVSurfacePlotVTK(QWidget *parent) : QVTKWidget(parent)
{
    loaded = false;
    generated = false;
    axisGenerated = false;
    externalData = false;
    verboseMode = true;
    consoleAssigned = false;
    closestTriad = true;
    antiAliasing = false;
    thresholded = false;
    autoScaleZ = false;
    logScaled = false;
    animating = false;
    pausedAnimation = false;

    scaling = 1.0;

    currentSlice = 0;

    createActions();
}

DGVSurfacePlotVTK::~DGVSurfacePlotVTK()
{
//    if(loaded)
//    {
//        if(!externalData)
//            plotData->Delete();
//    }
//    if(generated)
//    {
//        geometry->Delete();
//        warp->Delete();
//        surfaceNormals->Delete();
//        mapper->Delete();
//        lod->Delete();
//
//        //actor->Delete();
//        renderer->Delete();
//        renderWin->Delete();
//
//        if(logScaled)
//            logData->Delete();
//
//        //if(thresholded)
//            //imageThresholder->Delete();
//    }
//    if(axisGenerated)
//    {
//        axes->Delete();
//    }
    ///Smart Deletion on
    ///plotData, geometry, warp, surfaceNormals, mapper, lod, renderer, renderWin, logData, axes
}

void DGVSurfacePlotVTK::setName(QString filename)
{
    name = filename;
    setWindowTitle(strippedNamePrefix());

    emit nameChanged(strippedNamePrefix());
}

void DGVSurfacePlotVTK::setData(Array<imageType,2> data)
{
    QString tmp1, tmp2, tmp3;

    plotArray.resizeAndPreserve(data.shape());
    plotArray = data;

    plotData = Blitz.arrayToVTKImageData(plotArray);

    loaded = true;
    externalData = false;
    printInfo("SPlot Min: " + tmp1.setNum(Blitz.getMin()) + ", Data Max: " + tmp2.setNum(Blitz.getMax()) + ". Mean: " + tmp3.setNum(Blitz.getMean()));
}

void DGVSurfacePlotVTK::SetInput(vtkImageData *newData)
{
    QString tmp1, tmp2, tmp3;

    plotData = newData;
    externalData = true;
    loaded = true;
    Blitz.vtkImageDataToArray(plotData,plotArray);
    printInfo("SPlot Min: " + tmp1.setNum(Blitz.getMin()) + ", Data Max: " + tmp2.setNum(Blitz.getMax()) + ". Mean: " + tmp3.setNum(Blitz.getMean()));
}

void DGVSurfacePlotVTK::setScaleFactor(double factor)
{
    if(loaded && generated)
    {
        scaling = factor;
        warp->SetScaleFactor(factor);
        warp->Update();

        renderer->ResetCamera();
        renderWin->Render();
    }
}

void DGVSurfacePlotVTK::setXLabel(QString text)
{
    if(axisGenerated)
    {
        axes->SetXLabel(text.toStdString().c_str());
    }
}

void DGVSurfacePlotVTK::setYLabel(QString text)
{
    if(axisGenerated)
    {
        axes->SetYLabel(text.toStdString().c_str());
    }
}

void DGVSurfacePlotVTK::setZLabel(QString text)
{
    if(axisGenerated)
    {
        axes->SetZLabel(text.toStdString().c_str());
    }
}

void DGVSurfacePlotVTK::setAxesAsClosestTriad()
{
    if(axisGenerated)
    {
        axes->SetFlyModeToClosestTriad();
    }
}

void DGVSurfacePlotVTK::setAxesAsOuterEdges()
{
    if(axisGenerated)
    {
        axes->SetFlyModeToOuterEdges();
    }
}

void DGVSurfacePlotVTK::setBackground(double r, double g, double b)
{
    if(loaded && generated)
    {
        renderer->SetBackground(r, g, b);
        renderWin->Render();
    }
}

bool DGVSurfacePlotVTK::saveVTI(const QString filename)
{
    if(loaded && generated)
    {
        vtkXMLImageDataWriter* writer = vtkXMLImageDataWriter::New();

        writer->SetInput(plotData);
        writer->SetFileName(filename.toStdString().c_str());
        writer->SetDataModeToBinary();
        writer->Write();
        writer->Delete();

        return true;
    }
    else
        return false;
}

void DGVSurfacePlotVTK::generatePlot()
{
    if(loaded)
    {
        geometry = PlotGeometry::New();
        warp = PlotWarp::New();
        surfaceNormals = PlotNorms::New();
        mapper = PlotMapper::New();

        setupSurface();

        lod = PlotLOD::New();
        renderer = Renderer::New();
        renderWin = RenderWindow::New();

        lod->SetMapper(mapper);
        renderer->TwoSidedLightingOn();
        renderer->LightFollowCameraOn();
        renderer->AddActor(lod);
        renderer->ResetCamera();
        renderer->SetBackground(0.1, 0.2, 0.4);
        renderer->ResetCameraClippingRange();
        renderWin->AddRenderer(renderer);
        QVTKWidget::SetRenderWindow(renderWin);

        setupEvents();

        if(bounds[1] > minWindowSize || bounds[3] > minWindowSize)
        {
            renderWin->SetSize(bounds[1],bounds[3]);
            QVTKWidget::resize(bounds[1],bounds[3]);
        }
        else
        {
            renderWin->SetSize(minWindowSize,minWindowSize);
            QVTKWidget::resize(minWindowSize,minWindowSize);
        }

        generated = true;
    }
}

void DGVSurfacePlotVTK::generatePlotMergedWith(vtkImageData *image)
{
    if(loaded)
    {
        if(!generated)
        {
            QString tmp1, tmp2, tmp3;

            geometry = PlotGeometry::New();
            warp = PlotWarp::New();
            surfaceNormals = PlotNorms::New();
            mapper = PlotMapper::New();
            vtkMergeFilter *merge = vtkMergeFilter::New();

            ///\todo Bug: Using plotData for everything and converting causes crash on destruction.
            //Blitz.convertCoordinatesToArray(plotData);
            plotData = image;
            externalData = true;
            geometry->SetInput(image);
            image->GetExtent(bounds);
            ///\todo Bug: If values within grid are too large, then surface warp fails. Needs proper scaling.
            ///\todo Bug: Colour images dont merge correctly with mono data.
            warp->SetInputConnection(geometry->GetOutputPort());
            printInfo("SPlot Min: " + tmp1.setNum(Blitz.getMin()) + ", Data Max: " + tmp2.setNum(Blitz.getMax()) + ". Mean: " + tmp3.setNum(Blitz.getMean()));
            scaling = 0.2*( 1.0 / ( 2.0*(Blitz.getMax()-Blitz.getMin()) / (bounds[1]+bounds[3]) ) );
            warp->SetScaleFactor(scaling);
            warp->SetNormal(0, 0, 1);
            warp->UseNormalOn();
            //warp->ReleaseDataFlagOn();

            merge->SetGeometry(warp->GetOutput());
            merge->SetScalars(image);
            surfaceNormals->SetInputConnection(merge->GetOutputPort());
            //surfaceNormals->ReleaseDataFlagOn();
            mapper->SetInputConnection(surfaceNormals->GetOutputPort());
            mapper->SetScalarRange(Blitz.getMin(),Blitz.getMax());
            //mapper->ReleaseDataFlagOn();
            mapper->Update();

            lod = PlotLOD::New();
            renderer = Renderer::New();
            renderWin = RenderWindow::New();

            lod->SetMapper(mapper);
            renderer->TwoSidedLightingOn();
            renderer->LightFollowCameraOn();
            renderer->AddActor(lod);
            renderer->ResetCamera();
            renderer->SetBackground(0.1, 0.2, 0.4);
            renderer->ResetCameraClippingRange();
            renderWin->AddRenderer(renderer);
            QVTKWidget::SetRenderWindow(renderWin);

            setupEvents();

            if(bounds[1] > minWindowSize || bounds[3] > minWindowSize)
            {
                renderWin->SetSize(bounds[1],bounds[3]);
                QVTKWidget::resize(bounds[1],bounds[3]);
            }
            else
            {
                renderWin->SetSize(minWindowSize,minWindowSize);
                QVTKWidget::resize(minWindowSize,minWindowSize);
            }
            generated = true;
            Blitz.alignmentForImages(false); //!< Align correctly

            merge->Delete();
        }
    }
}

void DGVSurfacePlotVTK::generateAxes()
{
    if(loaded && generated)
    {
        double ranges[6];
        if(!axisGenerated)
            axes = PlotAxes::New();

        ///Axes
        axes->SetInput(warp->GetOutput());
        axes->SetCamera(renderer->GetActiveCamera());
        axes->SetLabelFormat("%6.4g");
        if(!closestTriad)
            axes->SetFlyModeToOuterEdges();
        else
            axes->SetFlyModeToClosestTriad();
        axes->SetFontFactor(0.8);

        ///Ensure z-scale is true
        axes->UseRangesOn();
        ranges[0] = 1.0;
        ranges[1] = static_cast<double>(bounds[1]+1);
        ranges[2] = 1.0;
        ranges[3] = static_cast<double>(bounds[3]+1);
        if(!logAct->isChecked())
        {
            ranges[4] = static_cast<double>(Blitz.getMin());
            ranges[5] = static_cast<double>(Blitz.getMax());
        }
        else
        {
            ranges[4] = static_cast<double>( log(1+Blitz.getMin()) );
            ranges[5] = static_cast<double>( log(1+Blitz.getMax()) );
        }
        axes->SetRanges(ranges);

        renderer->AddViewProp(axes);
        renderer->ResetCamera();
        renderer->SetBackground(0.1, 0.2, 0.4);
        renderer->ResetCameraClippingRange();
        renderWin->AddRenderer(renderer);
        QVTKWidget::SetRenderWindow(renderWin);

        axisGenerated = true;
    }
}

void DGVSurfacePlotVTK::refresh()
{
    if(loaded && generated)
    {
        QString tmp, tmp1, tmp2, tmp3;

        plotData = Blitz.arrayToVTKImageData(plotArray);
        plotData->GetExtent(bounds);
        printInfo("Refreshing " + strippedNamePrefix() + ", z = " + tmp3.setNum(currentSlice) + ", " + tmp1.setNum(bounds[1]) + "x" + tmp2.setNum(bounds[3]));

        updateDisplayData();

        if(axisGenerated)
            generateAxes();

        renderWin->Render();
    }
}

void DGVSurfacePlotVTK::renameData()
{
    bool ok;

    QString newName = QInputDialog::getText(this, tr("Rename Data"), tr("New Name: "), QLineEdit::Normal, name, &ok);

    if(ok)
        setName(newName);
}

void DGVSurfacePlotVTK::animateFromSlices(Array<imageType,3> *data, int interval)
{
    //if(isVisible()) //Otherwise no point
    //{
        QTimer *timer = new QTimer(this);

        volumeData = data;
        connect(timer, SIGNAL(timeout()), this, SLOT(updateSlice()));
        cerr << "Volume Array Size: " << volumeData->rows() << "x" << volumeData->cols() << "x" << volumeData->depth() << endl;

        currentSlice = 0;
        setData((*volumeData)(Range::all(),Range::all(),currentSlice));
        currentSlice ++;
        generatePlot();
        generateAxes();
        animating = true;

        timer->start(interval);
    //}
}

QString DGVSurfacePlotVTK::strippedName()
{
    return QFileInfo(name).fileName();
}

QString DGVSurfacePlotVTK::strippedNamePrefix()
{
    return "SPlot: " + QFileInfo(name).fileName();
}

void DGVSurfacePlotVTK::setConsole(DGVConsole *newConsole)
{
    if(newConsole != NULL)
    {
        console = newConsole;
        consoleAssigned = true;
    }
}

void DGVSurfacePlotVTK::scale()
{
    bool ok;

    double newScaling = QInputDialog::getDouble(this, tr("z-axis Scale Factor"),
                                          tr("Scale Factor:"), scaling, 0, 2147483647, 16, &ok);
    cerr << "Scaling : " << scaling << endl;
    if(ok)
        setScaleFactor(newScaling);
}

void DGVSurfacePlotVTK::threshold()
{
    if(loaded && generated)
    {
        thresholder = new ThresholdForm(parentWidget(),Qt::Horizontal,QwtSlider::TopScale);

        //printWarning("Thresholding ");
        thresholder->setMax(Blitz.getMax());
        thresholder->setMin(Blitz.getMin());
        //thresholder->setNoOfMajorTicks(10);
        //thresholder->setNoOfMinorTicks(4);
        thresholder->setUpperValue(Blitz.getMax());
        connect(thresholder, SIGNAL(upperValueChanged(double)), this, SLOT(thresholdUpper(double)));
        connect(thresholder, SIGNAL(lowerValueChanged(double)), this, SLOT(thresholdLower(double)));
        thresholded = true;

        thresholder->show();
    }
}

void DGVSurfacePlotVTK::thresholdUpper(double value)
{
    QString tmp;

    if(loaded && generated && thresholded)
    {
        printWarning("Thresholding Upper at: " + tmp.setNum(value));

        vtkImageThreshold *thres = vtkImageThreshold::New();

        thres->SetInput(plotData);
        thres->ThresholdBetween(thresholder->getLowerValue(),value);
        thres->Update();

        geometry->SetInput(thres->GetOutput());
        geometry->Update();

        if(axisGenerated)
            generateAxes();

        renderWin->Render();
    }
}

void DGVSurfacePlotVTK::thresholdLower(double value)
{
    QString tmp;

    if(loaded && generated && thresholded)
    {
        printWarning("Thresholding Lower at: " + tmp.setNum(value));

        vtkImageThreshold *thres = vtkImageThreshold::New();

        thres->SetInput(plotData);
        thres->ThresholdBetween(value,thresholder->getUpperValue());
        thres->Update();

        geometry->SetInput(thres->GetOutput());

        if(axisGenerated)
            generateAxes();

        renderWin->Render();
    }
}

void DGVSurfacePlotVTK::xLabel()
{
    bool ok;
    QString text = QInputDialog::getText(this, tr("x-axis Label"),
                                          tr("New Label:"), QLineEdit::Normal,
                                          "x", &ok);
    if(ok)
        setXLabel(text);
}

void DGVSurfacePlotVTK::yLabel()
{
    bool ok;
    QString text = QInputDialog::getText(this, tr("y-axis Label"),
                                          tr("New Label:"), QLineEdit::Normal,
                                          "y", &ok);
    if(ok)
        setYLabel(text);
}

void DGVSurfacePlotVTK::zLabel()
{
    bool ok;
    QString text = QInputDialog::getText(this, tr("z-axis Label"),
                                          tr("New Label:"), QLineEdit::Normal,
                                          "z", &ok);
    if(ok)
        setZLabel(text);
}

void DGVSurfacePlotVTK::background()
{
    double colours[3];
    bool ok1, ok2, ok3;

    if(generated)
    {
        renderer->GetBackground(colours);
        double red = QInputDialog::getDouble(this, tr("New Background Colour"), tr("Red Component (0.0-1.0): "), colours[0], 0, 1, 2, &ok1);
        double green = QInputDialog::getDouble(this, tr("New Background Colour"), tr("Green Component (0.0-1.0): "), colours[1], 0, 1, 2, &ok2);
        double blue = QInputDialog::getDouble(this, tr("New Background Colour"), tr("Blue Component (0.0-1.0): "), colours[2], 0, 1, 2, &ok3);

        if(ok1 && ok2 && ok3)
            setBackground(red,green,blue);
    }
}

void DGVSurfacePlotVTK::axesProperties()
{
    bool ok1, ok2, ok3, ok4;

    if(axisGenerated)
    {
        double colours[3], factor = 1.0;
        vtkProperty2D *properties = axes->GetProperty();
        vtkTextProperty *txtProperties = axes->GetAxisTitleTextProperty();

        properties->GetColor(colours);
        factor = axes->GetFontFactor();
        double red = QInputDialog::getDouble(this, tr("New Axis Colour"), tr("Red Component (0.0-1.0): "), colours[0], 0, 1, 2, &ok1);
        double green = QInputDialog::getDouble(this, tr("New Axis Colour"), tr("Green Component (0.0-1.0): "), colours[1], 0, 1, 2, &ok2);
        double blue = QInputDialog::getDouble(this, tr("New Axis Colour"), tr("Blue Component (0.0-1.0): "), colours[2], 0, 1, 2, &ok3);
        factor = QInputDialog::getDouble(this, tr("New Axis Font Factor"), tr("Font Factor: "), factor, 0, 100, 3, &ok4);

        if(ok1 && ok2 && ok3 && ok4)
        {
            properties->SetColor(red,green,blue);
            txtProperties->ShadowOff();
            txtProperties->SetColor(red,green,blue);
            axes->SetFontFactor(factor);
            axes->SetProperty(properties);
            axes->SetAxisTitleTextProperty(txtProperties);
            axes->SetAxisLabelTextProperty(txtProperties);
            renderWin->Render();
        }
    }
}

void DGVSurfacePlotVTK::updateDisplayData()
{
    if(loaded && generated)
    {
        if(logAct->isChecked())
        {
            printWarning("Using Log Scale: This is experimental.");

            if(!logScaled)
                logData = PlotLogScale::New();

            logData->SetInput(plotData);
            //vtkImageData *tmpImage = logData->GetOutput();
            //Blitz.convertCoordinatesToArray(tmpImage);
            geometry->SetInput(logData->GetOutput());
            geometry->Update();

            if(autoScaleZ || !logScaled)
            {
                scaling = 1.0/( 2.0*(log(1+Blitz.getMax())-log(1+Blitz.getMin())) / (bounds[1]+bounds[3]) );
                setScaleFactor(scaling);
            }

            logScaled = true;
            if(!logScaled)
                renderer->ResetCamera();
        }
        else
        {
            geometry->SetInput(plotData);
            geometry->Update();
            if(autoScaleZ)
            {
                scaling = 1.0/( 2.0*(Blitz.getMax()-Blitz.getMin()) / (bounds[1]+bounds[3]) );
                setScaleFactor(scaling);
            }

            if(logScaled)
            {
                //logData->Delete();
                scaling = 1.0/( 2.0*(Blitz.getMax()-Blitz.getMin()) / (bounds[1]+bounds[3]) );
                setScaleFactor(scaling);
                logScaled = false;
                renderer->ResetCamera();
            }
        }
        renderWin->Render();
    }
}

void DGVSurfacePlotVTK::toggleAxesAsClosestTriad()
{
    closestTriad = triadAct->isChecked();
    if(closestTriad)
        setAxesAsClosestTriad();
    else
        setAxesAsOuterEdges();
}

void DGVSurfacePlotVTK::toggleAntiAliasing()
{
    if(generated)
    {
        antiAliasing = antiAliasingAct->isChecked();
        if(antiAliasing)
        {
            renderWin->SetAAFrames(maxAASamples);
            renderWin->Render();
        }
        else
        {
            renderWin->SetAAFrames(0);
            renderWin->Render();
        }
    }
}

void DGVSurfacePlotVTK::save()
{
    if(loaded && generated)
    {
        QFileDialog *fileSaver = new QFileDialog(this);
        QSettings settings("Shakes", "DGV");

        QString path = settings.value("recentPath").toString();
        QString filename = fileSaver->getSaveFileName(this,
                                       tr("Select File Name to Save"),
                                       path,
                                       tr("VTK XML Image Files (*.vti)"));

        saveVTI(filename);
    }
}

void DGVSurfacePlotVTK::setupEvents()
{
    ///Unbind the right mouse button events as Qt uses context menu.
    QVTKWidget::GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonPressEvent);
    QVTKWidget::GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonReleaseEvent);
}

void DGVSurfacePlotVTK::setupSurface()
{
    QString tmp, tmp1, tmp2, tmp3;

    geometry->SetInput(plotData);
    geometry->Update();
    plotData->GetExtent(bounds);
    printInfo("Surface plot size: " + tmp1.setNum(bounds[1]) + "x" + tmp2.setNum(bounds[3]));

    ///\todo Bug: If values within grid are too large, then surface warp fails. Needs proper scaling.
    warp->SetInputConnection(geometry->GetOutputPort());
    scaling = 1.0/( 2.0*(Blitz.getMax()-Blitz.getMin()) / (bounds[1]+bounds[3]) );
    printInfo("Scaled z-axis by " + tmp.setNum(scaling));
    printInfo("SPlot Min: " + tmp1.setNum(Blitz.getMin()) + ", Data Max: " + tmp2.setNum(Blitz.getMax()) + ". Mean: " + tmp3.setNum(Blitz.getMean()));
    warp->SetScaleFactor(scaling);
    warp->SetNormal(0, 0, 1);
    warp->UseNormalOn();
    //warp->ReleaseDataFlagOn();

    surfaceNormals->SetInputConnection(warp->GetOutputPort());
    //surfaceNormals->ReleaseDataFlagOn();
    surfaceNormals->Update();
    mapper->SetInputConnection(surfaceNormals->GetOutputPort());
    mapper->SetScalarRange(Blitz.getMin(),Blitz.getMax());
    mapper->Update();
    //mapper->ReleaseDataFlagOn();
}

void DGVSurfacePlotVTK::updateSlice()
{
    if(!pausedAnimation)
    {
        plotArray = (*volumeData)(Range::all(),Range::all(),currentSlice);
        currentSlice ++;
        currentSlice %= volumeData->depth();
        refresh();
    }
}

void DGVSurfacePlotVTK::pauseAnimation()
{
    if(pausedAnimation)
        pausedAnimation = false;
    else
        pausedAnimation = true;
}

void DGVSurfacePlotVTK::contextMenuEvent(QContextMenuEvent *event)
{
    contextMenu = new QMenu(this); //!< Only exists for the duration of the context selection

    ///Global Ops
    scaleAct = contextMenu->addAction(tr("&Scale Factor"));
    scaleAct->setShortcut(tr("Ctrl+s"));
    connect(scaleAct, SIGNAL(triggered()), this, SLOT(scale()));
    thresholdAct = contextMenu->addAction(tr("&Threshold"));
    thresholdAct->setShortcut(tr("Ctrl+t"));
    thresholdAct->setDisabled(true);
    connect(thresholdAct, SIGNAL(triggered()), this, SLOT(threshold()));
    contextMenu->addSeparator()->setText("Axes");
    ///Labels and Options
    xLabelAct = contextMenu->addAction(tr("Set &x Label"));
    xLabelAct->setShortcut(tr("Ctrl+x"));
    connect(xLabelAct, SIGNAL(triggered()), this, SLOT(xLabel()));
    yLabelAct = contextMenu->addAction(tr("Set &y Label"));
    yLabelAct->setShortcut(tr("Ctrl+y"));
    connect(yLabelAct, SIGNAL(triggered()), this, SLOT(yLabel()));
    zLabelAct = contextMenu->addAction(tr("Set &z Label"));
    zLabelAct->setShortcut(tr("Ctrl+z"));
    connect(zLabelAct, SIGNAL(triggered()), this, SLOT(zLabel()));
    backgroundAct = contextMenu->addAction(tr("Set &Background Colour"));
    backgroundAct->setShortcut(tr("Ctrl+b"));
    connect(backgroundAct, SIGNAL(triggered()), this, SLOT(background()));
    axesAct = contextMenu->addAction(tr("Set &Axes Colour/Font"));
    axesAct->setShortcut(tr("Ctrl+a"));
    connect(axesAct, SIGNAL(triggered()), this, SLOT(axesProperties()));
    contextMenu->addAction(logAct);
    ///Setup Toggle Options
    triadAct = contextMenu->addAction(tr("Axes as Closest Triad"));
    triadAct->setCheckable(true);
    triadAct->setChecked(closestTriad);
    connect(triadAct, SIGNAL(triggered()), this, SLOT(toggleAxesAsClosestTriad()));
    antiAliasingAct = contextMenu->addAction(tr("Anti-Aliasing"));
    antiAliasingAct->setCheckable(true);
    antiAliasingAct->setChecked(antiAliasing);
    connect(antiAliasingAct, SIGNAL(triggered()), this, SLOT(toggleAntiAliasing()));
    contextMenu->addSeparator()->setText(tr("Animation"));
    ///Animation Controls
    startAct = contextMenu->addAction(tr("&Restart"));
    startAct->setDisabled(!animating);
    connect(startAct, SIGNAL(triggered()), this, SLOT(firstSlice()));
    pauseAct = contextMenu->addAction(tr("&Pause/Unpause"));
    pauseAct->setDisabled(!animating);
    connect(pauseAct, SIGNAL(triggered()), this, SLOT(pauseAnimation()));
    contextMenu->addSeparator();
	///Setup Close action
	///Close
	saveAct = contextMenu->addAction(tr("Save Surface Data..."));
	saveAct->setShortcut(tr("Ctrl+s"));
	connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
	refreshAct = contextMenu->addAction(tr("Re&fresh"));
	connect(refreshAct, SIGNAL(triggered()), this, SLOT(refresh()));
	renameAct = contextMenu->addAction(tr("Rename"));
	renameAct->setShortcut(tr("Ctrl+r"));
	connect(renameAct, SIGNAL(triggered()), this, SLOT(renameData()));
	closeAct = contextMenu->addAction(tr("Close"));
	closeAct->setShortcut(tr("Ctrl+q"));
	connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));

	contextMenu->exec(event->globalPos());
}

void DGVSurfacePlotVTK::printError(QString msg)
{
    if(verboseMode)
    {
        if(consoleAssigned)
        {
            console->printError(msg);
        }
        else
            cerr << msg.toStdString() << endl;
    }
}

void DGVSurfacePlotVTK::printWarning(QString msg)
{
    if(verboseMode)
    {
        if(consoleAssigned)
        {
            console->printWarning(msg);
        }
        else
            cerr << msg.toStdString() << endl;
    }
}

void DGVSurfacePlotVTK::printInfo(QString msg)
{
    if(verboseMode)
    {
        if(consoleAssigned)
        {
            console->printInfo(msg);
        }
        else
            cerr << msg.toStdString() << endl;
    }
}

void DGVSurfacePlotVTK::createActions()
{
    logAct = new QAction(this);
    logAct->setText(QApplication::translate("Plot", "&Log Scale", 0, QApplication::UnicodeUTF8));
    logAct->setShortcut(tr("Ctrl+l"));
    logAct->setCheckable(true);
}

void DGVSurfacePlotVTK::createConnections()
{
    connect(logAct, SIGNAL(triggered()), this, SLOT(refresh()));
}
